package com.imay.videorecord.encoder.view;

import android.content.Context;
import android.graphics.SurfaceTexture;
import android.opengl.EGL14;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;

import com.imay.videorecord.camera.CameraEngine;
import com.imay.videorecord.camera.utils.CameraInfo;
import com.imay.videorecord.encoder.MediaEncoder;
import com.imay.videorecord.encoder.MediaVideoEncoder;
import com.imay.videorecord.encoder.video.TextureMovieEncoder;
import com.imay.videorecord.filter.base.MagicCameraInputFilter;
import com.imay.videorecord.filter.base.gpuimage.OpenGlUtils;
import com.imay.videorecord.filter.helper.MagicFilterType;
import com.imay.videorecord.utils.ImayParams;
import com.imay.videorecord.utils.ImayUtils;

import java.io.File;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import static com.imay.videorecord.camera.CameraEngine.releaseCamera;
import static com.imay.videorecord.camera.CameraEngine.startPreview;
import static com.umeng.socialize.utils.DeviceConfig.context;


/**
 * Created by zhouzechao on 2016/12/27. 备注
 */
public class MagicCameraView extends MagicBaseView implements MediaEncoder.MediaEncoderListener {

    private final String TAG = MagicCameraView.class.getSimpleName();

    private MagicCameraInputFilter cameraInputFilter;

    private SurfaceTexture surfaceTexture;

    private RecordStatusListener recordListener;
    private MagicFilterType mType;
    private boolean mIsVolue = true;

    public MagicCameraView(Context context) {
        this(context, null);
    }

    private boolean recordingEnabled;
    private int recordingStatus;

    private static final int RECORDING_OFF = 0;
    private static final int RECORDING_ON = 1;
    private static final int RECORDING_RESUMED = 2;
    private TextureMovieEncoder videoEncoder;

    private String outputFilePath;
    private String outputFileName;

    public MagicCameraView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.getHolder().addCallback(this);

        videoEncoder = new TextureMovieEncoder(this.getContext());
        recordingStatus = -1;
        recordingEnabled = false;
        scaleType = ScaleType.CENTER_CROP;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        super.onSurfaceCreated(gl, config);

        // 录制数据初始化
        if (videoEncoder != null) {
            recordingEnabled = videoEncoder.isRecording();
        } else {
            recordingEnabled = false;
        }
        if (recordingEnabled) {
            recordingStatus = RECORDING_RESUMED;
        } else {
            recordingStatus = RECORDING_OFF;
        }

        if (cameraInputFilter == null)
            cameraInputFilter = new MagicCameraInputFilter(getContext());
        cameraInputFilter.init();

        if (textureId == OpenGlUtils.NO_TEXTURE) {
            textureId = OpenGlUtils.getExternalOESTextureID();
            surfaceTexture = new SurfaceTexture(textureId);
            surfaceTexture.setOnFrameAvailableListener(onFrameAvailableListener);
        }
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        super.onSurfaceChanged(gl, width, height);
        openCamera(width, height);
        if (mType != null) {
            setFilter(mType);
        }
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        super.onDrawFrame(gl);
        if (surfaceTexture == null)
            return;
        //Log.i(TAG,"5-----onDrawFrame");
        surfaceTexture.updateTexImage();
        if (recordingEnabled) {
            //Log.i(TAG,"4-----onDrawFrame");
            switch (recordingStatus) {
                case RECORDING_OFF: // 开始录制
                    Log.i(TAG, "6-----RECORDING_OFF");
                    if (mType != null) {
                        videoEncoder.setFilter(mType);
                    }

                    File outputFile = ImayUtils.getOutputMediaFile(getContext(), ImayUtils.MEDIA_TYPE_VIDEO);
                    outputFilePath = outputFile.getAbsolutePath();
                    outputFileName = outputFile.getName();

                    // 屏幕的信息
                    CameraInfo info = CameraEngine.getCameraInfo();
                    videoEncoder.setPreviewSize(info.previewWidth, info.pictureHeight);
                    videoEncoder.setTextureBuffer(gLTextureBuffer);
                    videoEncoder.setCubeBuffer(gLCubeBuffer);
                    // movie的配置清单项
                    TextureMovieEncoder.EncoderConfig config = new TextureMovieEncoder.EncoderConfig(
                            outputFilePath, 640, 640,
                            1000000, mIsVolue, EGL14.eglGetCurrentContext(), this);
                    // 开始录制
                    videoEncoder.startRecording(config);
                    recordingStatus = RECORDING_ON;
                    break;
                case RECORDING_RESUMED:
                    videoEncoder.updateSharedContext(EGL14.eglGetCurrentContext());
                    recordingStatus = RECORDING_ON;
                    break;
                case RECORDING_ON:
                    break;
                default:
                    throw new RuntimeException("unknown status " + recordingStatus);
            }
        } else {
            switch (recordingStatus) {
                case RECORDING_ON:
                case RECORDING_RESUMED:
                    if (videoEncoder != null) {
                        videoEncoder.stopRecording();
                    }
                    recordingStatus = RECORDING_OFF;
                    break;
                case RECORDING_OFF:
                    break;
                default:
                    throw new RuntimeException("unknown status " + recordingStatus);
            }
        }


        /**
         * surface画面绘制
         */
        float[] mtx = new float[16];
        surfaceTexture.getTransformMatrix(mtx);
        cameraInputFilter.setTextureTransformMatrix(mtx);
        int id = textureId;
        if (filter == null) {
            cameraInputFilter.onDraw(textureId, gLCubeBuffer, gLTextureBuffer);
        } else {
            id = cameraInputFilter.onDrawToTexture(textureId);
            filter.onDraw(id, gLCubeBuffer, gLTextureBuffer);
        }

        /**
         * 录制设置对应的纹理
         */
        if (videoEncoder != null && recordingStatus == RECORDING_ON) {
            videoEncoder.setTextureId(id);
            videoEncoder.frameAvailable(surfaceTexture);
        }
    }

    private SurfaceTexture.OnFrameAvailableListener onFrameAvailableListener = new SurfaceTexture.OnFrameAvailableListener() {

        @Override
        public void onFrameAvailable(SurfaceTexture surfaceTexture) {
            requestRender();
        }
    };

    @Override
    public void setFilter(MagicFilterType type) {
        super.setFilter(type);
        mType = type;
        if (videoEncoder != null) {
            videoEncoder.setFilter(type);
        }
    }

    public void resumeCamera() {
        CameraEngine.resumeCamera(surfaceWidth, surfaceHeight);
    }

    public void pauceCamera() {
        CameraEngine.pauceCamera();
    }

    public void switchCamera() {
        CameraEngine.switchCamera(surfaceWidth, surfaceHeight);
        CameraInfo info = CameraEngine.getCameraInfo();
        if(info == null){
            if (surfaceTexture != null)
                startPreview(surfaceTexture);
            return;
        }
        if (info.orientation == 90 || info.orientation == 270) {
            imageWidth = info.previewHeight;
            imageHeight = info.previewWidth;
        } else {
            imageWidth = info.previewWidth;
            imageHeight = info.previewHeight;
        }
        cameraInputFilter.onInputSizeChanged(imageWidth, imageHeight);
        adjustSize(info.orientation, info.isFront, true);
        if (surfaceTexture != null)
            startPreview(surfaceTexture);

        //这里是新加的代码，调整前置摄像头拍照后,画面翻转跟预览旋转问题.
        //要问我为什么,我也不知道,就是被我调试出来了.这样可以解决.adjustSize里面设置问题。
        if (info.isFront) {
            setSwitchCamera();
        }

        if (mType != null) {
            setFilter(mType);
        }
    }

    private void openCamera(int width, int height) {
        if (CameraEngine.getCamera() == null)
            CameraEngine.openCamera(ImayParams.OPEN_CAMERA_ID, width, height);
        CameraInfo info = CameraEngine.getCameraInfo();
        if(info == null){
            CameraEngine.startPreview(surfaceTexture);
            return;
        }
        if (info.orientation == 90 || info.orientation == 270) {
            imageWidth = info.previewHeight;
            imageHeight = info.previewWidth;
        } else {
            imageWidth = info.previewWidth;
            imageHeight = info.previewHeight;
        }
        cameraInputFilter.onInputSizeChanged(imageWidth, imageHeight);
        //这里是新加的代码，调整前置摄像头拍照后,画面翻转跟预览旋转问题.
        //要问我为什么,我也不知道,就是被我调试出来了.这样可以解决.adjustSize里面设置问题。
        if (info.isFront) {
            setSwitchCamera();
        } else {
            adjustSize(info.orientation, info.isFront, true);
            if (surfaceTexture != null)
                CameraEngine.startPreview(surfaceTexture);
        }
    }

    public void setSwitchCamera() {
        adjustSize(90, false, true);
        if (surfaceTexture != null)
            CameraEngine.startPreview(surfaceTexture);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        super.surfaceDestroyed(holder);
        releaseCamera();
    }

    public void changeRecordingState(boolean isRecording) {
        recordingEnabled = isRecording;
        if (recordListener != null) {
            recordListener.onRecordStatus(recordingEnabled, getOutFilePath(), getFileName());
        }
    }

    @Override
    protected void onFilterChanged() {
        super.onFilterChanged();
        if (cameraInputFilter != null) {
            cameraInputFilter.onOutputSizeChanged(surfaceWidth, surfaceHeight);
            if (filter != null)
                cameraInputFilter.initCameraFrameBuffer(imageWidth, imageHeight);
            else
                cameraInputFilter.destroyFramebuffers();
        }
    }

    public void onBeautyLevelChanged() {
        cameraInputFilter.onBeautyLevelChanged();
    }

    /**
     * 获取文件路径
     *
     * @return
     */
    public String getOutFilePath() {
        return outputFilePath;
    }

    /**
     * 获取文件名
     *
     * @return
     */
    public String getFileName() {
        return outputFileName;
    }

    public void setRecordListener(RecordStatusListener recordListener) {
        this.recordListener = recordListener;
    }

    public void release() {
        if (videoEncoder != null) {
            videoEncoder.releaseEncoder();
            videoEncoder = null;
        }
    }

    @Override
    public void onPrepared(final MediaEncoder encoder) {
        if (encoder instanceof MediaVideoEncoder) {
            Log.i(TAG, "onPrepared");
            recordListener.onPrepared();
            recordListener.onStarted();
        }
    }

    @Override
    public void onStopped(MediaEncoder encoder) {
        if (encoder instanceof MediaVideoEncoder) {
            Log.i(TAG, "onStopped");
        }
    }

    @Override
    public void onMuxerStopped() {
        Log.i(TAG, "onMuxerStopped");
        recordListener.onFinished();
    }

    /**
     * 是否有录音权限
     *
     * @param isVolue
     */
    public void setIsVolue(boolean isVolue) {
        mIsVolue = isVolue;
    }
}
